{
 "cells": [
  {
   "cell_type": "code",
   "execution_count": 42,
   "metadata": {},
   "outputs": [],
   "source": [
    "class Dog:\n",
    "    id_count = 0\n",
    "    \n",
    "    @classmethod\n",
    "    def generate_id(cls):\n",
    "        cls.id_count += 1\n",
    "        return cls.id_count\n",
    "    \n",
    "    def __init__(self, breed, color, size):\n",
    "        self.id = str(self.generate_id()).zfill(5)\n",
    "        self.breed = breed\n",
    "        self.color = color\n",
    "        self.size = size\n",
    "        \n",
    "    def eat(self):\n",
    "        print('Eating bones...')\n",
    "        \n",
    "    def run(self):\n",
    "        print('running...')\n",
    "        \n",
    "    def bark(self):\n",
    "        print('Wof! Wof!')\n",
    "        print(self.breed, self.color, self.size)\n",
    "\n",
    "        "
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 43,
   "metadata": {},
   "outputs": [],
   "source": [
    "dog1 = Dog(breed='Haiski', color='white', size='medium')\n",
    "dog2 = Dog(breed='Haiski', color='white', size='medium')\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 44,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "__main__.Dog"
      ]
     },
     "execution_count": 44,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "type(dog1)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 45,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Eating bones...\n"
     ]
    }
   ],
   "source": [
    "dog1.eat()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 46,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "running...\n"
     ]
    }
   ],
   "source": [
    "dog2.run()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 47,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Wof! Wof!\n",
      "Haiski white medium\n"
     ]
    }
   ],
   "source": [
    "dog1.bark()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 50,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "00001 Haiski white medium\n"
     ]
    }
   ],
   "source": [
    "print(dog1.id, dog1.breed, dog1.color, dog1.size)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 53,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "00002 Haiski white medium\n"
     ]
    }
   ],
   "source": [
    "print(dog2.id, dog2.breed, dog2.color, dog2.size)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 56,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "00003\n",
      "00004\n",
      "00005\n",
      "00006\n",
      "00007\n",
      "00008\n",
      "00009\n",
      "00010\n",
      "00011\n",
      "00012\n"
     ]
    }
   ],
   "source": [
    "for _ in range(10):\n",
    "    d = Dog(breed='Haiski', color='white', size='medium')\n",
    "    print(d.id)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 57,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "12\n"
     ]
    }
   ],
   "source": [
    "print(Dog.id_count)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 58,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "['__class__',\n",
       " '__delattr__',\n",
       " '__dict__',\n",
       " '__dir__',\n",
       " '__doc__',\n",
       " '__eq__',\n",
       " '__format__',\n",
       " '__ge__',\n",
       " '__getattribute__',\n",
       " '__gt__',\n",
       " '__hash__',\n",
       " '__init__',\n",
       " '__init_subclass__',\n",
       " '__le__',\n",
       " '__lt__',\n",
       " '__module__',\n",
       " '__ne__',\n",
       " '__new__',\n",
       " '__reduce__',\n",
       " '__reduce_ex__',\n",
       " '__repr__',\n",
       " '__setattr__',\n",
       " '__sizeof__',\n",
       " '__str__',\n",
       " '__subclasshook__',\n",
       " '__weakref__',\n",
       " 'bark',\n",
       " 'breed',\n",
       " 'color',\n",
       " 'eat',\n",
       " 'generate_id',\n",
       " 'id',\n",
       " 'id_count',\n",
       " 'run',\n",
       " 'size']"
      ]
     },
     "execution_count": 58,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "dir(d)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 276,
   "metadata": {},
   "outputs": [],
   "source": [
    "# Good: name, price, discount rate\n",
    "# Cart: good, good_num\n",
    "class Good:\n",
    "    \"\"\"商品類\"\"\"\n",
    "    id_count = 0\n",
    "    \n",
    "    # decorator\n",
    "    @classmethod\n",
    "    def generate_id(cls):\n",
    "        cls.id_count += 1\n",
    "        return cls.id_count\n",
    "    \n",
    "    def __init__(self, name, price, discount_rate=1):\n",
    "        self.id = str(self.generate_id()).zfill(5)\n",
    "        self.name = name\n",
    "        self.price = price\n",
    "        self.discount_rate = discount_rate\n",
    "        \n",
    "    def calc_price(self):\n",
    "        \"\"\"商品打折後的實際售價\"\"\"\n",
    "        return self.price * self.discount_rate\n",
    "\n",
    "    \n",
    "class Cart:\n",
    "    \"\"\"購物車\"\"\"\n",
    "    def __init__(self):\n",
    "        self.cart = {}\n",
    "        self.goods_list = []\n",
    "    \n",
    "    def add(self, goods, num=1):\n",
    "        if goods in self.goods_list:\n",
    "            self.cart[goods.id] += num\n",
    "        else:\n",
    "            self.goods_list.append(goods)\n",
    "            self.cart[goods.id] = num\n",
    "    \n",
    "    def remove(self, goods, num):\n",
    "        if goods not in self.goods_list:\n",
    "            return \n",
    "        self.cart[goods.id] -= num\n",
    "        # 更新後的情況\n",
    "        if self.cart[goods.id] <= 0:\n",
    "            del self.cart[goods.id]\n",
    "            self.goods_list.remove(goods)\n",
    "            \n",
    "    def get_good_by_id(self, id):\n",
    "        for good in self.goods_list:\n",
    "            if id == good.id:\n",
    "                return good\n",
    "            \n",
    "    def get_total_amount(self):\n",
    "        \"\"\"計算購物車的總價\"\"\"\n",
    "        total_amount = 0\n",
    "        for id, num in self.cart.items():\n",
    "            good = self.get_good_by_id(id)\n",
    "            total_amount += good.price * num\n",
    "        return total_amount\n",
    "    \n",
    "    def get_pay_amount(self):\n",
    "        \"\"\"計算購物車實際需要支付的總價\"\"\"\n",
    "        total_amount = 0\n",
    "        for id, num in self.cart.items():\n",
    "            good = self.get_good_by_id(id)\n",
    "            total_amount += good.calc_price() * num\n",
    "        return total_amount\n",
    "    \n",
    "    def show_cart(self):\n",
    "        title = ('商品', '單價', '數量', '價格(元)')\n",
    "        \n",
    "        def show_row(row):\n",
    "            \"\"\"內部函數，讓購物車的資訊以每行顯示\"\"\"\n",
    "            for col in row:\n",
    "                print(str(col).ljust(12), end='\\t')\n",
    "            print('')\n",
    "                \n",
    "        show_row(title)\n",
    "        for id, num in self.cart.items():\n",
    "            good = self.get_good_by_id(id)\n",
    "            price = '%.2f' % (good.price)\n",
    "            if good.discount_rate < 1:\n",
    "                price = '%.2f(%d折)' % (good.price, good.discount_rate * 10)\n",
    "            show_row((good.name, price, num, '%.2f' % (good.calc_price() * num)))\n",
    "        total_goods_amount = self.get_total_amount()\n",
    "        total_pay_amount = self.get_pay_amount()\n",
    "        discount_amount = total_goods_amount - total_pay_amount\n",
    "        show_row(('', '', '', '總金額：', '%.2f' % total_goods_amount))\n",
    "        if discount_amount > 0:\n",
    "            show_row(('', '', '', '優惠抵減：', '%.2f' % discount_amount))\n",
    "        show_row(('', '', '', '實付金額：', '%.2f' % total_pay_amount))\n",
    "        \n",
    "    "
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 277,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "iPhone11 6000 5400.0\n"
     ]
    }
   ],
   "source": [
    "g1 = Good('iPhone11', 6000, 0.9)\n",
    "g2 = Good('USB', 108, 0.8)\n",
    "g3 = Good('Leveno', 15000)\n",
    "\n",
    "print(g1.name, g1.price, g1.calc_price())"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 278,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "USB 108 86.4\n"
     ]
    }
   ],
   "source": [
    "print(g2.name, g2.price, g2.calc_price())"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 279,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "{'00001': 1}\n"
     ]
    }
   ],
   "source": [
    "cart1 = Cart()\n",
    "cart1.add(g1)\n",
    "\n",
    "print(cart1.cart)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 280,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "{'00001': 1, '00002': 3}\n"
     ]
    }
   ],
   "source": [
    "cart1.add(g2, 3)\n",
    "\n",
    "print(cart1.cart)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 281,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "00001 iPhone11 1 6000\n",
      "00002 USB 3 324\n"
     ]
    }
   ],
   "source": [
    "for good in cart1.goods_list:\n",
    "    print(good.id, good.name, cart1.cart[good.id], good.price * cart1.cart[good.id])"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 282,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "6324\n"
     ]
    }
   ],
   "source": [
    "print(cart1.get_total_amount())"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 283,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "5659.2\n"
     ]
    }
   ],
   "source": [
    "print(cart1.get_pay_amount())"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 284,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "商品          \t單價          \t數量          \t價格(元)       \t\n",
      "iPhone11    \t6000.00(9折) \t1           \t5400.00     \t\n",
      "USB         \t108.00(8折)  \t3           \t259.20      \t\n",
      "            \t            \t            \t總金額：        \t6324.00     \t\n",
      "            \t            \t            \t優惠抵減：       \t664.80      \t\n",
      "            \t            \t            \t實付金額：       \t5659.20     \t\n"
     ]
    }
   ],
   "source": [
    "cart1.show_cart()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 288,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "商品          \t單價          \t數量          \t價格(元)       \t\n",
      "USB         \t108.00(8折)  \t2           \t172.80      \t\n",
      "            \t            \t            \t總金額：        \t216.00      \t\n",
      "            \t            \t            \t優惠抵減：       \t43.20       \t\n",
      "            \t            \t            \t實付金額：       \t172.80      \t\n"
     ]
    }
   ],
   "source": [
    "cart1.remove(g2, 1)\n",
    "cart1.show_cart()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 289,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "商品          \t單價          \t數量          \t價格(元)       \t\n",
      "USB         \t108.00(8折)  \t5           \t432.00      \t\n",
      "Leveno      \t15000.00    \t1           \t15000.00    \t\n",
      "iPhone11    \t6000.00(9折) \t2           \t10800.00    \t\n",
      "            \t            \t            \t總金額：        \t27540.00    \t\n",
      "            \t            \t            \t優惠抵減：       \t1308.00     \t\n",
      "            \t            \t            \t實付金額：       \t26232.00    \t\n"
     ]
    }
   ],
   "source": [
    "cart1.add(g3, 1)\n",
    "cart1.add(g1, 2)\n",
    "cart1.add(g2, 3)\n",
    "\n",
    "cart1.show_cart()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": []
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.8.5"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 4
}
